package com.cskaoyan.gateway.controller.promotion;

import com.cskaoyan.gateway.cache.CacheManager;
import com.google.common.util.concurrent.RateLimiter;
import com.mall.commons.result.ResponseData;
import com.mall.commons.result.ResponseUtil;
import com.mall.order.constant.OrderRetCode;
import com.mall.promo.PromoService;
import com.mall.promo.constant.PromoRetCode;
import com.mall.promo.dto.*;
import com.mall.user.constants.SysRetCodeConstants;
import com.mall.user.intercepter.TokenIntercepter;
import lombok.extern.slf4j.Slf4j;
import org.apache.dubbo.config.annotation.Reference;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

import javax.annotation.PostConstruct;
import javax.servlet.http.HttpServletRequest;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.concurrent.*;

/**
 * @Description:
 * @Author: JK
 * @Date: create in 2021/7/28 22:12
 */
@Slf4j
@RequestMapping("shopping")
@RestController
public class PromoController {
    @Reference(timeout = 3000, check = false)
    PromoService promoService;

    @Autowired
    CacheManager cacheManager;

    // 通过该工具实现令牌桶算法
    RateLimiter rateLimiter;

    // 线程池
    ExecutorService executorService;

    @PostConstruct
    public void init() {
        // 创建一个每秒产生100个令牌的令牌桶
        rateLimiter = RateLimiter.create(100);
        executorService = Executors.newFixedThreadPool(100);
    }

    @GetMapping("seckilllist")
    public ResponseData getPromoList(String sessionId) {
        PromoInfoRequest promoInfoRequest = new PromoInfoRequest();
        promoInfoRequest.setSessionId(Integer.parseInt(sessionId));
        Date date = new Date();
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyyMMdd");
        String yyyymmdd = simpleDateFormat.format(date);
        log.info("查询的秒杀场次yyyymmdd = " + yyyymmdd + ", sessionId = " + promoInfoRequest.getSessionId());
        promoInfoRequest.setYyyymmdd(yyyymmdd);

        PromoInfoResponse response = promoService.getPromoList(promoInfoRequest);

        if (PromoRetCode.SUCCESS.getCode().equals(response.getCode())) {
            return new ResponseUtil<>().setData(response);
        }

        return new ResponseUtil<>().setErrorMsg(response.getMsg());
    }

    @PostMapping("promoProductDetail")
    public ResponseData getPromoProductDetail(@RequestBody PromoProductDetailRequest request) {
        PromoProductDetailResponse response = promoService.getPromoProductDetail(request);

        if (PromoRetCode.SUCCESS.getCode().equals(response.getCode())) {
            return new ResponseUtil<>().setData(response);
        }

        return new ResponseUtil<>().setErrorMsg(response.getMsg());
    }

    @PostMapping("seckill")
    public ResponseData createPromoOrder(@RequestBody CreatePromoOrderRequest request, HttpServletRequest servletRequest) {
        // 总体请求的限流(使用令牌桶)
        // 如果获取令牌成功，继续向下执行；如果获取令牌失败，则阻塞等待
        rateLimiter.acquire();


        String uid = (String) servletRequest.getAttribute(TokenIntercepter.USER_INFO_KEY);
        request.setUserId(Long.parseLong(uid));

        log.info("秒杀商品的信息：{}", request);

        // 业务限流，没有库存则不处理该请求了
        // 判断秒杀商品是否售罄，如果售罄直接返回商品已售罄
        Long psId = request.getPsId();
        Long productId = request.getProductId();
        String StockNotEnough = "stock_not_enough_" + psId + "_" + productId;
        String StockNotEnoughValue = cacheManager.checkCache(StockNotEnough);
        if (StockNotEnoughValue != null && "stockNotEnough".equals(StockNotEnoughValue.trim())) {
            return new ResponseUtil<>().setErrorMsg(PromoRetCode.PROMO_ITEM_STOCK_NOT_ENOUGH.getMessage());
        }

        // 下游的服务调用放入线程池中执行
        Future<CreatePromoOrderResponse> future = executorService.submit(new Callable<CreatePromoOrderResponse>() {
            @Override
            public CreatePromoOrderResponse call() throws Exception {
                return promoService.createPromoOrderInTransaction(request);
            }
        });

        try {
            CreatePromoOrderResponse response = future.get();
            if (PromoRetCode.SUCCESS.getCode().equals(response.getCode())) {
                return new ResponseUtil<>().setData(response);
            } else {
                return new ResponseUtil<>().setErrorMsg(response.getMsg());
            }
        } catch (InterruptedException | ExecutionException e) {
            e.printStackTrace();
        }

//        CreatePromoOrderResponse response = promoService.createPromoOrder(request);

//        CreatePromoOrderResponse response = promoService.createPromoOrderInTransaction(request);
//
//        if (PromoRetCode.SUCCESS.getCode().equals(response.getCode())) {
//            return new ResponseUtil<>().setData(response);
//        }

        return new ResponseUtil<>().setErrorMsg(SysRetCodeConstants.SYSTEM_ERROR.getMessage());
    }
}
